<!DOCTYPE html>
<html lang="en">
<head>
	<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport">
	<meta charset="utf-8">
	<title>杂项设置</title>
	<script>
		var d = document;
		var loc = false, locip, locproto = "http:";
		function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
		function B() { window.open(getURL("/settings"),"_self"); }
		function U() { window.open(getURL("/update"),"_self"); }
		function gId(s) { return d.getElementById(s); }
		function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
		// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
		function loadJS(FILE_URL, async = true) {
			let scE = d.createElement("script");
			scE.setAttribute("src", FILE_URL);
			scE.setAttribute("type", "text/javascript");
			scE.setAttribute("async", async);
			d.body.appendChild(scE);
			// success event 
			scE.addEventListener("load", () => {
				//console.log("File loaded");
				GetV();
				setBckFilename(gId("bckcfg"));
				setBckFilename(gId("bckpresets"));
			});
			// error event
			scE.addEventListener("error", (ev) => {
				console.log("Error on loading file", ev);
				alert("Loading of configuration script failed.\nIncomplete page data!");
			});
		}
		var timeout;
		function showToast(text, error = false)
		{
			var x = gId("toast");
			x.innerHTML = text;
			x.classList.add(error ? "error":"show");
			clearTimeout(timeout);
			x.style.animation = 'none';
			timeout = setTimeout(function(){ x.classList.remove("show"); }, 2900);
		}
		function uploadFile(fO,name) {
			var req = new XMLHttpRequest();
			req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
			req.addEventListener('error', function(e){showToast(e.stack,true);});
			req.open("POST", getURL("/upload"));
			var formData = new FormData();
			formData.append("data", fO.files[0], name);
			req.send(formData);
			fO.value = '';
			return false;
		}
		function checkNum(o) {
			const specialkeys = ["Backspace", "Tab", "Enter", "Shift", "Control", "Alt", "Pause", "CapsLock", "Escape", "Space", "PageUp", "PageDown", "End", "Home", "ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown", "Insert", "Delete"];
			// true if key is a number or a special key
			if(event.key.match(/[0-9]/) || specialkeys.includes(event.key)) return true;
			event.preventDefault();
			return false;
		}
		function setBckFilename(x) {
			x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
		}
		function S() {
			let l = window.location;
			if (l.protocol == "file:") {
				loc = true;
				locip = localStorage.getItem('locIp');
				if (!locip) {
					locip = prompt("文件模式. 请输入WLED IP!");
					localStorage.setItem('locIp', locip);
				}
			} else {
				// detect reverse proxy
				let path = l.pathname;
				let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
				if (paths.length > 2) {
					locproto = l.protocol;
					loc = true;
					locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
				}
			}
			if (loc) {
				gId("bckcfg").setAttribute('href',getURL(gId("bckcfg").pathname));
				gId("bckpresets").setAttribute('href',getURL(gId("bckpresets").pathname));
			}
			loadJS(getURL('/settings/s.js?p=6'), false);	// If we set async false, file is loaded and executed, then next statement is processed
			if (loc) d.Sf.action = getURL('/settings/sec');
		}
		function getURL(path) {
			return (loc ? locproto + "//" + locip : "") + path;
		}
	</script>
	<style>
		@import url("style.css");
	</style>
</head>
<body onload="S()">
	<form id="form_s" name="Sf" method="post">
		<div class="toprow">
		<div class="helpB"><button type="button" onclick="H()">?</button></div>
		<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
		</div>
		<h2>安全和更新设置</h2>
		设置PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
		<div class="warn">&#9888; 未加密的传输。选择PIN时要谨慎，不要使用银行、门、SIM等PIN！</div><br>
		本地无线 (OTA)软件更新: <input type="checkbox" name="NO"><br>
		密码短语: <input type="password" name="OP" maxlength="32"><br>
		为了启用 OTA, 出于安全原因，您还需要输入正确的密码！<br>
		启用OTA时应更改密码.<br>
		<b>不使用时禁用OTA，否则攻击者可以重新刷新设备软件!</b><br>
		<i>只有禁用OTA锁定时，才能更改此页面上的设置!</i><br>
		如果锁定，则拒绝访问WiFi设置: <input type="checkbox" name="OW"><br><br>
		出厂设置: <input type="checkbox" name="RS"><br>
		所有设置和预设都将被清除.<br><br>
		<div class="warn">&#9888; 未加密的传输。同一网络上的攻击者可以截获表单数据!</div>
		<hr>
		<h3>软件更新</h3>
		<button type="button" onclick="U()">Manual OTA Update</button><br>
		启用ArduinoOTA: <input type="checkbox" name="AO">
		<hr>
		<h3>备份和恢复</h3>
		<a class="btn lnk" id="bckcfg" href="/presets.json" download="presets">备份预设</a><br>
		<div>恢复预设<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">上传</button><br></div><br>
		<a class="btn lnk" id="bckpresets" href="/cfg.json" download="cfg">备份配置</a><br>
		<div>恢复配置<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">上传</button><br></div>
		<div class="warn">&#9888; 恢复预设/配置将覆盖您当前的预设/配置。<br>
		配置不正确可能需要进行出厂重置或重新刷新ESP。</div>
		出于安全原因，不备份密码。
		<hr>
		<h3>About</h3>
		<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> 版本 ##VERSION##<!-- Autoreplaced from package.json --><br><br>
		<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-and-credits" target="_blank">贡献者、依赖关系和特别感谢</a><br>
		非常感谢所有帮助我创建WLED的人!<br><br>
		(c) 2016-2023 Christian Schwinne <br>
		<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
		服务信息: <span class="sip"> Response error! </span><hr>
		<div id="toast"></div>
		<button type="button" onclick="B()">返回</button><button type="submit">保存</button>
	</form>
</body>
</html>